package net.simflow.swf.analyzer.graph.opt;

import java.awt.Color;
import java.awt.Paint;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import net.simflow.swf.analyzer.data.ColorPkg;
import net.simflow.swf.analyzer.network.data.Node;
import net.simflow.swf.analyzer.network.data.Service;

import org.apache.commons.collections15.Transformer;

public class NodeToPaintTransformer implements Transformer<Node, Paint> {
	private static final int STYLE_ERROR = -1;
	private static final int STYLE_IO = 0;
	private static final int STYLE_COUNT = 1;
	private static final int STYLE_DEGREE = 2;

	private int style;

	private HashMap<Service, Integer> countMap;
	private int maxCount;

	private int maxDegree;

	public static NodeToPaintTransformer makeInstanceError() {
		return new NodeToPaintTransformer(STYLE_ERROR);
	}

	public static NodeToPaintTransformer makeInstanceIO() {
		return new NodeToPaintTransformer(STYLE_IO);
	}

	public static NodeToPaintTransformer makeInstanceCount(
			HashMap<Service, Integer> countMap) {
		if (countMap == null) {
			return new NodeToPaintTransformer(STYLE_ERROR);
		}
		return new NodeToPaintTransformer(STYLE_COUNT, countMap);
	}

	public static NodeToPaintTransformer makeInstanceDegree(
			Collection<? extends Integer> degreeSet) {
		if (degreeSet == null) {
			return new NodeToPaintTransformer(STYLE_ERROR);
		}
		return new NodeToPaintTransformer(STYLE_DEGREE, degreeSet);
	}

	private NodeToPaintTransformer(int style) {
		this.style = style;
	}

	private NodeToPaintTransformer(int style, HashMap<Service, Integer> countMap) {
		this.style = style;
		this.countMap = countMap;
		List<Integer> set = new ArrayList<Integer>(countMap.values());
		Collections.sort(set);
		maxCount = set.get(set.size() - 1);
	}

	private NodeToPaintTransformer(int style,
			Collection<? extends Integer> degreeSet) {
		this.style = style;
		List<Integer> set = new ArrayList<Integer>(degreeSet);
		Collections.sort(set);
		maxDegree = set.get(set.size() - 1);
	}

	@Override
	public Paint transform(Node node) {
		switch (style) {
		case STYLE_ERROR:
			return ColorPkg.TRANSPARENT;
		case STYLE_IO:
			return transformIO(node);
		case STYLE_COUNT:
			return transformCount(node);
		case STYLE_DEGREE:
			return transformDegree(node);
		}
		return ColorPkg.TRANSPARENT;
	}

	private Paint transformIO(Node node) {
		if (node.getChildDataSet().isEmpty()
				&& node.getParentDataSet().isEmpty()
				&& node.getChildControlSet().isEmpty()
				&& node.getParentControlSet().isEmpty()) {
			return ColorPkg.TRANSPARENT;
		}
		if (node.getParentDataSet().isEmpty()
				&& node.getParentControlSet().isEmpty()) {
			return this.toColor(ColorPkg.RED, 72);
		}
		if (node.getChildDataSet().isEmpty()
				&& node.getChildControlSet().isEmpty()) {
			return this.toColor(ColorPkg.BLUE, 72);
		}
		if (node.getService().getWsdlURI() != null) {
			return this.toColor(ColorPkg.GREEN, 72);
		}
		return this.toColor(ColorPkg.YELLOW, 72);
	}

	private Paint transformCount(Node node) {
		int c = countMap.get(node.getService());
		if (c >= 0 && c <= maxCount) {
			return this.toColor(ColorPkg.DARK_GREEN, getAlpha(maxCount, c));
		}
		return ColorPkg.TRANSPARENT;
	}

	private Paint transformDegree(Node node) {
		int d = node.getLinkCount();
		if (d >= 0 && d <= maxDegree) {
			return this.toColor(ColorPkg.DARK_BLUE, getAlpha(maxDegree, d));
		}
		return ColorPkg.TRANSPARENT;
	}

	private int getAlpha(int max, int c) {
		if (max <= 0) {
			return 0;
		}
		int alpha = (int) (Math.pow(c, 1.2) * 255d / Math.pow(max, 1.2));
		if (alpha < 0) {
			alpha = 0;
		} else if (alpha > 255) {
			alpha = 255;
		}
		return alpha;
	}

	private Color toColor(Color color, int alpha) {
		return new Color(color.getRed(), color.getGreen(), color.getBlue(),
				alpha);
	}
}
